package com.qys.livesMall.navy.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Sets;
import com.qys.livesMall.anchor.constants.RedisConstant;
import com.qys.livesMall.anchor.mapper.AnchorLivesSessionMapper;
import com.qys.livesMall.anchor.model.entity.AnchorLivesSession;
import com.qys.livesMall.app.user.constants.TencentCloudImConstant;
import com.qys.livesMall.app.user.model.entity.H2AppUserAddress;
import com.qys.livesMall.app.user.model.entity.H2AppUserBalance;
import com.qys.livesMall.app.user.service.IH2AppUserAddressService;
import com.qys.livesMall.app.user.service.IH2AppUserBalanceService;
import com.qys.livesMall.app.user.utils.TencentCloudIm;
import com.qys.livesMall.cache.RedisCache;
import com.qys.livesMall.common.exception.enums.ExceptionEnum;
import com.qys.livesMall.common.message.MessageServer;
import com.qys.livesMall.common.result.R;
import com.qys.livesMall.finance.model.entity.user.FinanceUserAccount;
import com.qys.livesMall.navy.common.Constant;
import com.qys.livesMall.navy.dao.NavyTaskDao;
import com.qys.livesMall.navy.dao.NavyTaskDetailDao;
import com.qys.livesMall.navy.model.dto.task.AddLiveOrder;
import com.qys.livesMall.navy.model.entity.NavyTask;
import com.qys.livesMall.navy.model.entity.NavyTaskDetail;
import com.qys.livesMall.navy.service.NavyLivesOrderService;
import com.qys.livesMall.navy.service.NavyTaskDetailService;
import com.qys.livesMall.navy.service.NavyTaskService;
import com.qys.livesMall.navy.service.NavyTaskTX;
import com.qys.livesMall.navy.task.TaskInter;
import com.qys.livesMall.shop.mapper.ShopGoodsInfoMapper;
import com.qys.livesMall.shop.mapper.ShopGoodsSkuStocksMapper;
import com.qys.livesMall.shop.modal.dto.shop.order.NavyAddOrder;
import com.qys.livesMall.shop.modal.entity.ShopGoodsSku;
import com.qys.livesMall.shop.modal.entity.ShopGoodsSkuStocks;
import com.qys.livesMall.shop.modal.entity.ShopOrder;
import com.qys.livesMall.shop.open.anchor.service.AnchorServer;
import com.qys.livesMall.shop.service.ShopGoodsSkuService;
import com.qys.livesMall.shop.service.api.impl.ShopOrderService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.qys.livesMall.navy.common.Constant.TaskType.lIVES_ORDER;

@Slf4j
@Service
public class NavyLivesOrderServiceImpl implements NavyLivesOrderService {

    @Resource
    private MessageServer messageServer;

    @Resource
    private IH2AppUserAddressService ih2AppUserAddressService;

    @Resource
    private ShopOrderService shopOrderService;

    @Resource
    private IH2AppUserBalanceService ih2AppUserBalanceService;

    @Resource
    private ShopGoodsInfoMapper shopGoodsInfoMapper;
    @Resource
    private ShopGoodsSkuService shopGoodsSkuService;

    @Resource
    private TaskInter taskInter;

    @Resource
    private NavyTaskDao navyTaskDao;
    @Resource
    private NavyTaskDetailDao navyTaskDetailDao;
    @Resource
    private AnchorLivesSessionMapper livesSessionMapper;
    @Resource
    private ShopGoodsSkuStocksMapper shopGoodsSkuStocksMapper;
    @Resource
    private TencentCloudIm tencentCloudIm;
    @Resource
    private AnchorServer anchorServer;
    @Resource
    private RedisCache redisCache;


    @Override
    public R livesOrder(AddLiveOrder param) {
        if (param==null|| CollectionUtils.isEmpty(param.getNavyIds())||CollectionUtils.isEmpty(param.getLiveIds())
                || null == param.getAmount()){
            return messageServer.failMsg(ExceptionEnum.PARAM_IS_ERROR);
        }
        //1、获取所有水军账户
        List<FinanceUserAccount> balances=ih2AppUserBalanceService.listByUserIds(param.navyIds.stream().map(Long::valueOf).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(balances)){
            log.error("直播下单:未获取到水军账户:{}",param.getNavyIds());
            return R.fail("未获取到水军账户:" + param.getNavyIds());
        }

        //创建任务
        NavyTask task = new NavyTask();
        task.setTaskType(lIVES_ORDER);
        task.setTaskStatus(Constant.TaskStatus.RUNNING);
        task.setTaskParam(JSONObject.toJSONString(param));
        task.setTaskStartTime(LocalDateTime.now());
        task.setCreateDate(LocalDateTime.now());
        task.setAmount(param.getAmount());
        task.setTaskName("直播下单");
        navyTaskDao.save(task);

        taskInter.addLivesOrderTask(1, task.getId());
        return R.ok();
    }

    @Override
    @Async
    public void exc(Long taskId) {

        //获取未完成的直播下单任务
        NavyTask shopOrderTask = navyTaskDao.getById(taskId);
        if(shopOrderTask == null){
            log.info("未查询到需要执行的直播下单任务");
            return;
        }
        log.info("查询到直播下单任务：{}", shopOrderTask.getId());

        //主任务参数
        AddLiveOrder liveOrder = JSONObject.parseObject(shopOrderTask.getTaskParam(), AddLiveOrder.class);
        List<String> navyIds = liveOrder.getNavyIds();
        //打乱排序，保证随机性
        Collections.shuffle(navyIds);

        //当前可下单金额
        BigDecimal amountAvailable;

        //最后执行的一条子任务
        NavyTaskDetail one = navyTaskDetailDao.getOne(Wrappers.<NavyTaskDetail>lambdaQuery().eq(NavyTaskDetail::getTaskId, shopOrderTask.getId()).orderByDesc(NavyTaskDetail::getTaskDate).last("limit 1"));
        if(one != null){
            log.info("直播下单最后执行的一条子任务:{}",JSONObject.toJSONString(one));
            amountAvailable = one.getAmount();
        } else {
            amountAvailable = liveOrder.getAmount();
        }


        //获取所有直播间商品（当前可下单金额内）
        List<Long> onLiveGoodsInfo = shopGoodsInfoMapper.getOnLiveGoodsInfo(liveOrder.getLiveIds());
        if(CollectionUtils.isEmpty(onLiveGoodsInfo)){
            log.info("没有进行中的直播，结束主任务");
            //没有进行中的直播，结束主任务
            NavyTask navyTask = new NavyTask();
            navyTask.setId(shopOrderTask.getId());
            navyTask.setTaskStatus(Constant.TaskStatus.END);
            navyTask.setTaskEndTime(LocalDateTime.now());
            navyTask.setRemark("没有进行中的直播，结束主任务");
            navyTaskDao.updateById(navyTask);
            return;
        }
        log.info("onLiveGoodsInfo:{}", onLiveGoodsInfo);

        List<ShopGoodsSku> skuList = shopGoodsSkuService.list(Wrappers.<ShopGoodsSku>lambdaQuery().in(ShopGoodsSku::getShopGoodsId, onLiveGoodsInfo));
        log.info("skuList:{}", skuList);
        //打乱排序，保证随机性
        Collections.shuffle(skuList);


        //匹配水军购买商品信息
        String byNavyId = null;
        ShopGoodsSku bySku = null;

        boolean ok = false;
        for (ShopGoodsSku shopGoodsSku : skuList) {
            //判断是否有库存
            ShopGoodsSkuStocks skuStocks = shopGoodsSkuStocksMapper.selectOne(Wrappers.<ShopGoodsSkuStocks>lambdaQuery()
                    .eq(ShopGoodsSkuStocks::getSkuId, shopGoodsSku.getId())
                    .ne(ShopGoodsSkuStocks::getNum, 0)
                    .orderByAsc(ShopGoodsSkuStocks::getCreateTime)
                    .last("limit 1")
            );
            if(skuStocks == null || skuStocks.getNum() == 0){
                continue;
            }
            BigDecimal price = skuStocks.getPrice();
            for (String navyId : navyIds) {
                H2AppUserBalance navyBalance = ih2AppUserBalanceService.queryByUserId(Long.valueOf(navyId));
                if(price.compareTo(navyBalance.getBalance()) <= 0){
                    byNavyId = navyId;
                    bySku = shopGoodsSku;
                    bySku.setPrice(price);
                    ok = true;
                    break;
                }
            }
            if (ok) {
                break;
            }
        }

        if(!ok){
            log.info("未匹配到商品，结束任务");
            NavyTask navyTask = new NavyTask();
            navyTask.setId(shopOrderTask.getId());
            navyTask.setTaskStatus(Constant.TaskStatus.END);
            navyTask.setTaskEndTime(LocalDateTime.now());
            navyTask.setRemark("未匹配到商品，结束任务");
            navyTaskDao.updateById(navyTask);
            return;
        }
        log.info("byNavyId:{},bySku:{}", byNavyId, JSONObject.toJSONString(bySku));

        //判断设置余额是否充足
        if(amountAvailable.subtract(bySku.getPrice()).compareTo(BigDecimal.ZERO) < 0){
            //批量下单余额已用尽，结束任务
            NavyTask navyTask = new NavyTask();
            navyTask.setId(shopOrderTask.getId());
            navyTask.setTaskStatus(Constant.TaskStatus.END);
            navyTask.setTaskEndTime(LocalDateTime.now());
            navyTask.setRemark("余额已用尽，结束任务");
            navyTaskDao.updateById(navyTask);
            log.info("批量下单余额已用尽，结束任务");
            return;
        }


        //下单商品来自哪个直播场次
        List<Long> livesSessionId = shopGoodsSkuService.getLivesSessionForSku(bySku.getSkuId(), liveOrder.getLiveIds());
        if(CollectionUtils.isEmpty(livesSessionId)){
            log.info("下单商品没有直播中的场次，结束主任务");
            //没有进行中的直播，结束主任务
            NavyTask navyTask = new NavyTask();
            navyTask.setId(shopOrderTask.getId());
            navyTask.setTaskStatus(Constant.TaskStatus.END);
            navyTask.setTaskEndTime(LocalDateTime.now());
            navyTask.setRemark("下单商品没有直播中的场次，结束主任务");
            navyTaskDao.updateById(navyTask);
            return;
        }
        log.info("下单商品来自直播场次:{}", livesSessionId);


        //获取水军收件地址
        H2AppUserAddress address = ih2AppUserAddressService.getByUserId(Long.valueOf(byNavyId));
        if (address == null){
            log.error("水军{}，没有默认地址", byNavyId);
            //跳过本次
            exc(shopOrderTask.getId());
        }
        log.info("获取水军用户地址成功");

        Long sessionId = livesSessionId.get(new Random().nextInt(livesSessionId.size()));
        AnchorLivesSession livesSession = livesSessionMapper.selectById(sessionId);


        //计入观看人数
        String key = RedisConstant.LIVE_ONLINE_NUMBER_PREFIX + sessionId;
        Long size = redisCache.size(key);
        Set<String> cacheSet;
        if(size == 0){
            cacheSet = Sets.newHashSet("navy" + byNavyId);
            //伪装进入直播间
            tencentCloudIm.sendGroupMsg(byNavyId, anchorServer.getRoomInfoByLivesSessionId(sessionId), TencentCloudImConstant.TIM_CUSTOM_ELEM, "enter");
        } else {
            cacheSet = redisCache.getCacheSet(key);
            if(!redisCache.getCacheSet(key).contains("navy" + byNavyId)){
                //伪装进入直播间
                tencentCloudIm.sendGroupMsg(byNavyId, anchorServer.getRoomInfoByLivesSessionId(sessionId), TencentCloudImConstant.TIM_CUSTOM_ELEM, "enter");
                cacheSet.add("navy" + byNavyId);
            }
        }
        redisCache.setCacheSet(key, cacheSet);

        try {
            Thread.sleep(RandomUtil.randomLong(5000, 10000));
        } catch (Exception ignored) {

        }

        //生成订单
        NavyAddOrder orderInfo=new NavyAddOrder();
        orderInfo.setUserId(Long.valueOf(byNavyId));
        orderInfo.setSkuId(bySku.getId());
        orderInfo.setTaskId(sessionId);
        orderInfo.setAnchorId(livesSession.getAnchorId());
        orderInfo.setNum(1);
        BeanUtils.copyProperties(address,orderInfo);
        orderInfo.setConsigUser(address.getUserName());
        ShopOrder shopOrder = shopOrderService.add(orderInfo);
        if (shopOrder.getOrderInfo() != null){
            shopOrderService.pay(shopOrder.getOrderInfo().getId());
        }
        log.info("下单成功");

        //如果购买成功保存数据
        NavyTaskDetail detail = new NavyTaskDetail();
        detail.setTaskId(shopOrderTask.getId());
        detail.setNavyIds(byNavyId);
        detail.setTaskType(lIVES_ORDER);
        detail.setAmount(amountAvailable.subtract(bySku.getPrice()));
        detail.setLivesIds(String.valueOf(sessionId));
        detail.setTaskStatus(Constant.TaskDetailStatus.END_SUCCESS);
        detail.setTaskDate(LocalDateTime.now());
        detail.setShopGoodsSkuIds(String.valueOf(bySku.getSkuId()));
        detail.setCreateDate(LocalDateTime.now());
        navyTaskDetailDao.save(detail);

        exc(shopOrderTask.getId());
    }
}
